#pragma once
#include <cstring>
#include <limits.h>
#include <cstdlib>
#include <sstream>
#include "redisObject.hpp"

namespace redisStruct
{
    class stringObject : public redisObject
    {
    public:
        char* _ptr = nullptr;
        size_t _size = 0;
        size_t _capcity = 0;

    private:
        bool IsCanTransToInt(const char* s, size_t slen, long& value) const
        {
            if (_encoding == TYPE_Encoding_INT)
                return true;

            char* endptr = nullptr;
            long  val = strtol(s, &endptr, 10);
            if (endptr[0] != '\0')//没有转到末尾
                return false;
            char buf[32] = { 0 };
            snprintf(buf, 32, "%ld", val);
            if (slen != strlen(buf) || memcmp(s, buf, slen))
                return false;

            value = val;

            return true;
        }



        void TransToSds()
        {
            if (_encoding == TYPE_Encoding_SDS)
                return;

            int number = (long)_ptr;
            _ptr = new char[32];
            _ptr[0] = 0;
            std::string str = std::to_string(number);
            memcpy(_ptr, str.c_str(), str.size());
            _ptr[str.size()] = 0;
            _capcity = 32;
            _size = str.size();
            _encoding = TYPE_Encoding_SDS;
        }

    public:
        stringObject(const char* ptr, size_t n) : redisObject(TYPE_STRING, TYPE_Encoding_SDS)
        {
            long value;
            if (IsCanTransToInt(ptr, n, value))
            {
                _encoding = TYPE_Encoding_INT;
                _ptr = (char*)value;
                return;
            }

            _ptr = new char[n + 1];
            memset(_ptr, 0, n + 1);
            memcpy(_ptr, ptr, n);
            _size = n;

            _capcity = n + 1;
        };
        ~stringObject() override
        {
            if (_encoding == TYPE_Encoding_SDS)
            {
                // delete _ptr;
                //cout << "~stringObject()" << endl;
                _ptr = nullptr;
            }
        }
        void reverse(size_t capacaty)
        {
            if (_capcity >= capacaty)
                return;

            char* ptr = new char[capacaty];
            memcpy(ptr, _ptr, _size);
            delete _ptr;
            _ptr = ptr;
            ptr = nullptr;
            _capcity = capacaty;
        }
        stringObject& append(const char* ptr, size_t n) // 添加字符串
        {

            TransToSds();

            if (_capcity - 1 < n + _size)
            {
                _capcity = n + _size + 1;
                char* temp = new char[_capcity];
                memcpy(temp, _ptr, _size + 1);
                delete _ptr;
                _ptr = temp;
                temp = nullptr;
            }

            memcpy(_ptr + _size, ptr, n);
            _size += n;
            _ptr[_size] = 0;

            long value;
            if (IsCanTransToInt(_ptr, n, value))
            {
                _encoding = TYPE_Encoding_INT;
                _ptr = (char*)value;
                return *this;
            }

            return *this;
        }
        void incrVal(int n)
        {
            if (_encoding == TYPE_Encoding_INT)
            {
                _ptr = (char*)((long)_ptr + n);
            }
            else
            {
                long long value = strtoll(_ptr, nullptr, 10);
                value += n;
                char buf[64] = { 0 };
                sprintf(buf, "lld", value);
                int len = strlen(buf);
                reverse(len + 1);
                memcpy(_ptr, buf, len + 1);
            }
        }
        void decrVal(int n)
        {
            if (_encoding == TYPE_Encoding_INT)
            {
                _ptr = (char*)((long)_ptr - n);
            }
            else
            {
                long long value = strtoll(_ptr, nullptr, 10);
                value -= n;
                char buf[64] = { 0 };
                sprintf(buf, "lld", value);
                int len = strlen(buf);
                reverse(len + 1);
                memcpy(_ptr, buf, len + 1);
            }
        }

        const char* c_str() const
        {
            return _ptr;
        }

         bool operator==(const stringObject& other_str_obj) const
        {
            if (_encoding != other_str_obj._encoding)
                return false;

            if (_encoding == TYPE_Encoding_INT)
                return (long)_ptr == (long)other_str_obj._ptr;

            if (_encoding == TYPE_Encoding_SDS && _size == other_str_obj._size)
            {
                for (int i = 0; i < _size; i++)
                    if (_ptr[i] != other_str_obj._ptr[i])
                        return false;
            }
            else
                return false;
            
            return true;
        }

        bool operator!=(const stringObject& other_str_obj) const
        {
            return !(*this == other_str_obj);
        }
        //左闭右闭
        stringObject* substr(int i, int j = (int)std::string::npos)
        {
            TransToSds();
            if (i >= _size) return nullptr;
            if (j < 0) j = _size + j;
            if (i > j) return nullptr;

            int size = _size < j - i + 1 ? _size : j - i + 1;
            stringObject* str1 = new stringObject(_ptr + i, size);
            str1->incrRefCount();
            long value;
            if (IsCanTransToInt(_ptr, _size, value))
            {
                _encoding = TYPE_Encoding_INT;
                delete _ptr;
                _ptr = (char*)atoi(_ptr);
            }
            return str1;

        }
    };

}